package com.zetatech.bdp.ftp.impl;

import com.zetatech.bdp.entity.FtpDFile;
import lombok.Cleanup;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class FTPUtil {

    public static FTPClient connect(String addr, int port, String username, String password, String controlEncoding) throws IOException {
        FTPClient client = new FTPClient();
        client.setControlEncoding(controlEncoding);
        client.connect(addr, port);
        username = (username == null || username.trim().isEmpty()) ? "Anonymous" : username;
        password = (username == null || username.trim().isEmpty()) ? "" : password;
        client.login(username, password);
        client.setFileType(FTPClient.BINARY_FILE_TYPE);
        int reply = client.getReplyCode();
        if (!FTPReply.isPositiveCompletion(reply)) {
            client.abort();
            client.disconnect();
        }
        return client;
    }

    public static void close(FTPClient client) throws IOException {
        if (client != null && client.isConnected()) {
            client.abort();
            client.disconnect();
        }
    }

    /**
     * 递归获取FTP服务器上满足特定要求的文件
     *
     * @param client
     * @param remotePath
     * @param dirPattern  过滤文件夹（正则）
     * @param filePattern 过滤文件(正则)
     * @return
     */
    public static List<String> listFiles(FTPClient client, String remotePath, String dirPattern, String filePattern) {
        List<String> files = new ArrayList<>();
        try {
            boolean result = client.changeWorkingDirectory(remotePath);
            FTPFile[] ftpFiles = client.listFiles();
            if (ftpFiles != null && ftpFiles.length > 0) {
                for (FTPFile ftpFile : ftpFiles) {
                    String name = ftpFile.getName();
                    String fullPath = remotePath + "/" + name;
                    if (ftpFile.isFile()) {
                        if (name.matches(filePattern)) {
                            files.add(fullPath);
                        }
                    } else {
                        if (name.matches(dirPattern)) {
                            files.addAll(listFiles(client, fullPath, dirPattern, filePattern));
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return files;
    }


    public static List<FtpDFile> download(FTPClient client, String remotePath, String dirPattern, String filePattern, String localStoreDir) throws Exception {
        List<String> remotePaths = listFiles(client, remotePath, dirPattern, filePattern);
        List<FtpDFile> result = new ArrayList<>();
        for (String _remotePath : remotePaths) {
            String[] items = _remotePath.split("/");
            String localDir = localStoreDir;
            String localName = items[items.length - 1];
            if (items.length > 1) {
                for (int i = 0; i < items.length - 1; i++) {
                    String item = items[i];
                    if (item != null && !item.isEmpty()) {
                        localDir = localDir + "/" + item;
                    }
                }
            }
            File localFile = new File(localDir, localName);
            boolean success = false;
            try {
                download(client, _remotePath, localFile.getAbsolutePath());
                success = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            result.add(new FtpDFile(_remotePath, localFile.getAbsolutePath(), success));
        }
        return result;
    }

    public static String download(FTPClient client, String remotePath, String localFullPath) throws Exception {
        File localFile = new File(localFullPath);
        if (localFile.exists()) {
            localFile.delete();
        } else {
            localFile.getParentFile().mkdirs();
        }
        @Cleanup OutputStream outputStream = new FileOutputStream(localFile);
        client.retrieveFile(remotePath, outputStream);
        outputStream.flush();
        return localFile.getAbsolutePath();
    }
}